package com.travel.sight.service.impl;

import com.travel.common.to.UpdateUserAttractionWeightTo;
import com.travel.common.to.UpdateUserTagWeightTo;
import com.travel.common.to.UserBehaviorWeightTo;
import com.travel.common.utils.R;
import com.travel.sight.entity.AttractionInfoEntity;
import com.travel.sight.entity.LikeEntity;
import com.travel.sight.feign.RecommendFeignService;
import com.travel.sight.service.AttractionInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.travel.common.utils.PageUtils;
import com.travel.common.utils.Query;

import com.travel.sight.dao.CollectionDao;
import com.travel.sight.entity.CollectionEntity;
import com.travel.sight.service.CollectionService;


@Service("collectionService")
public class CollectionServiceImpl extends ServiceImpl<CollectionDao, CollectionEntity> implements CollectionService {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    AttractionInfoService attractionInfoService;

    @Autowired
    RecommendFeignService recommendFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CollectionEntity> page = this.page(
                new Query<CollectionEntity>().getPage(params),
                new QueryWrapper<CollectionEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 是否收藏
     * @param attractionId
     * @param userId
     * @return
     */
    @Override
    public Boolean isCollection(Integer attractionId, Integer userId) {
        //1. 获取对应景点收藏过的 所有userId  collection_info:attraction_id_44
        String key = "collection_info:attraction_id_"+attractionId;
        List<String> userIdList = redisTemplate.opsForList().range(key, 0, -1);
        //2. 判断 这里取出的id为String 要转为string来判断
        boolean isCollection = userIdList.contains(String.valueOf(userId));
        return isCollection;
    }

    /**
     *1. 更新redis中的收藏数
     *2. 保存收藏记录到数据库
     * @param attractionId
     * @param userId
     */
    @Override
    public void saveCollection(Integer attractionId, Integer userId) {
        //1. 更改redis中的收藏数  key:attraction_info:43:collection_num  value:33
        String key = "attraction_info:"+ attractionId +":collection_num";
        String s = redisTemplate.opsForValue().get(key);
        //1.1 有记录 取出+1
        if(s != null && s.length() != 0){
            redisTemplate.opsForValue().increment(key);
        }else{
            //1.2 没有记录 添加
            redisTemplate.opsForValue().set(key,String.valueOf(1));
        }

        //2. 保存点赞记录到redis  key:collection_info:attraction_id_43 value: xx,xx,xx...
        String k = "collection_info:attraction_id_"+attractionId;
        redisTemplate.opsForList().leftPush(k,String.valueOf(userId));


        //3. 保存是从记录到数据库
        CollectionEntity collectionEntity = new CollectionEntity();
        collectionEntity.setUserId(userId);
        collectionEntity.setAttractionId(attractionId);
        collectionEntity.setAddTime(new Date());
        collectionEntity.setUpdateTime(new Date());
        this.save(collectionEntity);

        // TODO 后台对点收藏没有实时性要求，不特定去修改数据库中的点赞数
        // 启定时任务，每3分钟同步mysql和redis中的收藏数
    }

    /**
     * 删除收藏记录（redis+mysql）
     * @param attractionId
     * @param userId
     */
    @Override
    public void deleteCollection(Integer attractionId, Integer userId) {
        //1. 更改redis中的收藏数  key:attraction_info:43:collection_num  value:33
        String key = "attraction_info:"+ attractionId +":collection_num";
        redisTemplate.opsForValue().decrement(key);

        //2. redis中删除收藏记录
        redisTemplate.opsForList().remove("collection_info:attraction_id_"+attractionId, 0, String.valueOf(userId));

        //3. mysql中删除收藏记录
        this.baseMapper.delete(new QueryWrapper<CollectionEntity>()
                .eq("attraction_id",attractionId)
                .eq("user_id",userId));

        // TODO 后台对收藏没有实时性要求，不特定去修改数据库中的点赞数
        // 启定时任务，每3分钟同步mysql和redis中的收藏数
    }

    /**
     * 获取该用户收藏的次数
     * @param userId
     * @return
     */
    @Override
    public Integer getCollectionNumByUserId(Integer userId) {

        return this.baseMapper.selectCount(new QueryWrapper<CollectionEntity>().eq("user_id",userId));
    }

    /**
     * 1. 修改redis中的收藏数
     * 2. redis中添加收藏操作
     * 3. mysql中添加收藏操作
     * 4. 更新景点score
     * 5. 更新用户对该景点的权重
     * 6. 更新用户对景点标签的权重
     */
    @Override
    public void updateAfterCollection(Integer attractionId, Integer userId, Boolean isCollection) {
        UserBehaviorWeightTo weight = recommendFeignService.getUserBehaviorWeight();
        Double collectionWeight = weight.getCollectionWeight();

        //1. 修改redis中的收藏数 +1/-1
        //2. mysql中添加/删除收藏操作
        //3. redis中添加/删除收藏操作
        if(isCollection){ // 收藏过 -> 删除
            deleteCollection(attractionId,userId);
        }else{ // 没收藏过 -> 新增
            saveCollection(attractionId,userId);
        }

        //4. 计算并更新score（redis）
        //评分计算公式：(点击数/最大点击数 × 0.1 + 点赞数/最大点赞数 × 0.3 + 收藏数/最大收藏数 × 0.3 + 评论数/最大评论数 ×0.3 ) ×100
        //4.1 从redis中获取 最大点击数、最大点赞数、最大收藏数、最大评论数
        String maxClickKey = "max_value:click_num";
        String maxLikeKey = "max_value:like_num";
        String maxCollectionKey = "max_value:collection_num";
        String maxCommentKey = "max_value:comment_num";

        Integer maxClick = Integer.valueOf(redisTemplate.opsForValue().get(maxClickKey));
        Integer maxLike = Integer.valueOf(redisTemplate.opsForValue().get(maxLikeKey));
        Integer maxCollection = Integer.valueOf(redisTemplate.opsForValue().get(maxCollectionKey));
        Integer maxComment = Integer.valueOf(redisTemplate.opsForValue().get(maxCommentKey));

        //4.2 获取当前景点的 点击数、点赞数、收藏数、评论数（从redis获取，最新的）
        String clickKey = "attraction_info:"+attractionId+":click_num";
        String likeKey = "attraction_info:"+attractionId+":like_num";
        String collectionKey = "attraction_info:"+attractionId+":collection_num";
        String commentKey = "attraction_info:"+attractionId+":comment_num";

        Integer clickNum = Integer.valueOf(redisTemplate.opsForValue().get(clickKey));
        Integer likeNum = Integer.valueOf(redisTemplate.opsForValue().get(likeKey));
        Integer collectionNum = Integer.valueOf(redisTemplate.opsForValue().get(collectionKey));
        Integer commentNum = Integer.valueOf(redisTemplate.opsForValue().get(commentKey));

        //4.3 计算并更新score（redis）
        // 计算新的score值
        Double newScore = (clickNum.doubleValue() / maxClick.doubleValue() * 0.1 + likeNum.doubleValue() / maxLike.doubleValue() * 0.3 +
                collectionNum.doubleValue() / maxCollection.doubleValue() * 0.3 + commentNum.doubleValue() / maxComment.doubleValue() * 0.3) * 100;
        System.out.println("计算得到新的score为 "+newScore);

        String scoreKey = "attraction_info:"+attractionId+":score";
        redisTemplate.opsForValue().set(scoreKey,String.valueOf(newScore));

        //5. 更新用户对该景点的权重
        AttractionInfoEntity byId = attractionInfoService.getById(attractionId);

        UpdateUserAttractionWeightTo attractionWeightTo = new UpdateUserAttractionWeightTo();
        attractionWeightTo.setAttractionId(byId.getAttractionId());
        attractionWeightTo.setName(byId.getName());
        attractionWeightTo.setTag(byId.getTag());
        if(isCollection){ // 点赞过 -> 减权重
            attractionWeightTo.setWeight(collectionWeight*-1);
        }else{ // 没点赞过 -> 加权重
            attractionWeightTo.setWeight(collectionWeight);
        }

        R r1 = recommendFeignService.updateUserAttractionWeight(attractionWeightTo,userId);
        if(r1.getCode() == 0){
            System.out.println("更新用户对该景点的权重 成功");
        }else{
            System.out.println("更新用户对该景点的权重 失败");
        }

        //6. 更新用户对景点标签的权重
        UpdateUserTagWeightTo tagWeightTo = new UpdateUserTagWeightTo();
        tagWeightTo.setTagName(byId.getTag());
        if(isCollection){ // 点赞过 -> 减权重
            tagWeightTo.setWeight(collectionWeight*-1);
        }else{ // 没点赞过 -> 加权重
            tagWeightTo.setWeight(collectionWeight);
        }

        R r2 = recommendFeignService.updateUserTagWeight(tagWeightTo,userId);
        if(r2.getCode() == 0){
            System.out.println("更新用户对景点标签的权重 成功");
        }else{
            System.out.println("更新用户对景点标签的权重 失败");
        }
    }

}